package game

import (
	"context"
	"encoding/json"
	"game_server/dao/barrage"
	"game_server/dao/room"
	"game_server/framework/connection"
	"game_server/framework/global"
	"game_server/framework/message"
	"game_server/game/model"
	"game_server/proto"
	"game_server/tool"
	"github.com/duke-git/lancet/v2/convertor"
	"github.com/spf13/viper"
	"time"
)

var _gameManager *GameManager = nil

type GameManager struct {
	RoomInfos map[int]*model.RoomInfo
}

func GameManagerInstance() *GameManager {
	return _gameManager
}

func InitGameManager() *GameManager {
	if _gameManager != nil {
		return _gameManager
	}
	barragesInfos := make([]*model.Barrage, 0)
	barrages := barrage.QueryAll()
	for _, item := range barrages {
		barrageInfo := model.Barrage{}
		convertor.CopyProperties(&barrageInfo, &item)
		barragesInfos = append(barragesInfos, &barrageInfo)
	}
	roomInfos := make(map[int]*model.RoomInfo)
	roomsdb := room.QueryAll()
	for _, item := range roomsdb {
		roomConfig := model.RoomConfig{}
		convertor.CopyProperties(&roomConfig, &item)
		roomInfo := model.RoomInfoInitialize(&roomConfig, barragesInfos)
		roomInfos[roomConfig.RoomLevel] = roomInfo
	}
	_gameManager = &GameManager{RoomInfos: roomInfos}
	go _gameManager.checkPlayerStatus()
	return _gameManager
}

func (r *GameManager) JoinRoom(playerInfo *model.PlayerInfo, roomLevel int) {
	for _, v := range _gameManager.RoomInfos {
		_, ok := v.PlayerInfos.Get(playerInfo.Id)
		if ok {
			return
		}
	}
	_gameManager.RoomInfos[roomLevel].PlayerInfos.Set(playerInfo.Id, playerInfo)
}

func (r *GameManager) LevelRoom(playerId int64) {
	var roomInfo *model.RoomInfo = nil
	for _, v := range _gameManager.RoomInfos {
		ok := v.PlayerInfos.Has(playerId)
		if ok {
			roomInfo = v
		}
	}
	if roomInfo != nil {
		roomInfo.PlayerInfos.Range(func(k int64, v *model.PlayerInfo) bool {
			connectionWrapper := connection.ConnectionManagerInstance().QueryConnOne(v.Id)
			if connectionWrapper == nil {
				return true
			}
			messageWrapper := &message.MessageWrapper{
				Code: proto.ROOMEXIT,
				Data: playerId,
			}
			connectionWrapper.Receive(messageWrapper)
			return true
		})
		roomInfo.PlayerInfos.Delete(playerId)
	}
}

func (r *GameManager) QueryRoomInfo(playerId int64) *model.RoomInfo {
	for _, v := range _gameManager.RoomInfos {
		_, ok := v.PlayerInfos.Get(playerId)
		if ok {
			return v
		}
	}
	return nil
}

func (r *GameManager) checkPlayerStatus() {
	for {
		playerIds := make([]int64, 0)
		for _, roomInfo := range r.RoomInfos {
			roomInfo.PlayerInfos.Range(func(key int64, value *model.PlayerInfo) bool {
				if value.IsRobot {
					return true
				}
				playerIds = append(playerIds, key)
				return true
			})
		}
		for _, v := range playerIds {
			playerRd, err := global.RedisClient.Get(context.Background(), viper.GetString("redis.player-key")+convertor.ToString(v)).Result()
			if err != nil {
				r.LevelRoom(v)
				connection.InitConnectionManager().RemoveConn(v)
				global.Logger.Infof("player:%v token不存在", v)
			} else {
				playerInfo := &model.PlayerInfo{}
				json.Unmarshal([]byte(playerRd), playerInfo)
				currentTimestamp := tool.CurrentTimestamp()
				if playerInfo.IsGaming {
					continue
				}
				tokenTime := viper.GetInt("redis.token-time")
				if currentTimestamp-playerInfo.LastBetTimeStamp < int64(tokenTime)*1000*60 {
					continue
				}
				global.Logger.Infof("player:%v 离开房间", v)
				r.LevelRoom(v)
			}
		}
		time.Sleep(1 * time.Second)
	}
}
